﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

using XNAProjectLibrary;
using XNAProject.GameElements;



namespace XNAProject.Core
{
    public partial class XNAProjectCamera : Camera                                      //derives from camera!!!
    {
        private bool DEBUG = false;                                                     //not debugging

        private Vector3 angle = new Vector3();                                          //setting up vectors and matrices
        private Vector4 border;
        private Vector2 upDownBorder;
        public Matrix worldMatrix { get; set; }
        public Matrix renderMatrix { get; set; }
        public Matrix objectMatrix { get; set; }
        public float moveObject { get; set; }                                           //what is this used for?? --> Ha valami mozogna, ez a cucc az amennyivel mozog :) 

        public bool keysEnabled { get; set; }

        public XNAProjectCamera(Game game, Vector3 Position, Vector4 Border, Vector2 UpDownBorder, float MoveRate, float SpinRate,
            float ScrollWheelRate, float cameraPitch, float cameraYaw) 
            : base(game) 
        {
            this.Position = Position;                                                   //setting up camera values
            this.MoveRate = MoveRate;
            this.SpinRate = SpinRate;
            this.ScrollWheelRate = ScrollWheelRate;
            this.cameraPitch = cameraPitch;
            this.cameraYaw = cameraYaw;
            this.border = Border;
            this.upDownBorder = UpDownBorder;

            keysEnabled = true;
        }

        public override void Initialize()
        {
            worldMatrix = Matrix.Identity;                                              //initialize
            moveObject = 0;

            base.Initialize();                                                          //call base class initialize
        }

        public override void Update(GameTime gameTime)                                  //update TIMEBASED
        {
            float m = (float)gameTime.ElapsedGameTime.Milliseconds / 1000;              //elapsed gametime seconds
            moveObject += m;                                                            //--> Ha valami mozogna, ez a cucc az amennyivel mozog :)

            objectMatrix = Matrix.CreateTranslation(Vector3.Zero);                      //create object matrix
            renderMatrix = Matrix.CreateScale(1.0f);                                    //create rendermatrix
            renderMatrix = objectMatrix * renderMatrix;                                 //combine object and render matrices

            if (!DEBUG)
            {
                #region normal

                if (!UpdateInput)                                                       //only update if UpdateInput is true ->> !!! Nem megint XNA alap, csak akkor hajtsa végre a Parent Update függvényét, Parent itt a Camera (lásd Library)
                {
                    base.Update(gameTime);
                    return;
                }

                float timeDelta = (float)gameTime.ElapsedGameTime.TotalSeconds;         //elapsed game seconds

                if (keysEnabled)
                {
                    #region AWSD

                    if (input.KeyboardState.IsKeyDown(Keys.A) ||
                        (input.MouseState.X < 0) ||
                        (input.GamePads[playerIndex].ThumbSticks.Left.X < 0) ||
                        (input.GamePads[playerIndex].DPad.Left == ButtonState.Pressed))     //inputhandling WASD
                    {
                        if (cameraPosition.X > border.W)
                            cameraPosition.X -= MoveRate;
                    }

                    if (input.KeyboardState.IsKeyDown(Keys.D) ||
                        (input.MouseState.X > Game.GraphicsDevice.Viewport.Width) ||
                        (input.GamePads[playerIndex].ThumbSticks.Left.X > 360) ||
                        (input.GamePads[playerIndex].DPad.Right == ButtonState.Pressed))
                    {
                        if (cameraPosition.X < border.Z)
                            cameraPosition.X += MoveRate;
                    }

                    if (input.KeyboardState.IsKeyDown(Keys.W) ||
                        (input.MouseState.Y < 0) ||
                        (input.GamePads[playerIndex].ThumbSticks.Left.Y < 0) ||
                        (input.GamePads[playerIndex].DPad.Up == ButtonState.Pressed))
                    {
                        if (cameraPosition.Z > border.X)
                            cameraPosition.Z -= MoveRate;
                    }

                    if (input.KeyboardState.IsKeyDown(Keys.S) ||
                        (input.MouseState.Y > Game.GraphicsDevice.Viewport.Height) ||
                        (input.GamePads[playerIndex].ThumbSticks.Left.Y > 360) ||
                        (input.GamePads[playerIndex].DPad.Down == ButtonState.Pressed))
                    {
                        if (cameraPosition.Z < border.Y)
                            cameraPosition.Z += MoveRate;
                    }

                    #endregion

                    #region Arrows

                    //if (input.KeyboardState.IsKeyDown(Keys.Left) ||
                    //    (input.GamePads[playerIndex].ThumbSticks.Right.X < 0) ||
                    //    (input.GamePads[playerIndex].DPad.Left == ButtonState.Pressed))
                    //{
                    //    cameraYaw += (SpinRate * timeDelta);
                    //}
                    //if (input.KeyboardState.IsKeyDown(Keys.Right) ||
                    //    (input.GamePads[playerIndex].ThumbSticks.Right.X > 0) ||
                    //    (input.GamePads[playerIndex].DPad.Right == ButtonState.Pressed))
                    //{
                    //    cameraYaw -= (SpinRate * timeDelta);
                    //}

                    //if (input.KeyboardState.IsKeyDown(Keys.Down) ||
                    //    (input.GamePads[playerIndex].ThumbSticks.Right.Y < 0))
                    //{
                    //    cameraPitch -= (SpinRate * timeDelta);
                    //}
                    //if (input.KeyboardState.IsKeyDown(Keys.Up) ||
                    //    (input.GamePads[playerIndex].ThumbSticks.Right.Y > 0))
                    //{
                    //    cameraPitch += (SpinRate * timeDelta);
                    //}

                    #endregion
                }

                #region Mouse

#if !XBOX360

                if (input.MouseState.ScrollWheelValue < input.PreviousMouseState.ScrollWheelValue)
                {
                    if (cameraPosition.Y < upDownBorder.X)
                    {
                        cameraPosition.Y += ScrollWheelRate * 5;
                        cameraPitch -= (float)(ScrollWheelRate * 0.04);
                    }
                }
                else if (input.MouseState.ScrollWheelValue > input.PreviousMouseState.ScrollWheelValue)
                {
                    if (cameraPosition.Y > upDownBorder.Y)
                    {
                        cameraPosition.Y -= ScrollWheelRate * 5;
                        cameraPitch += (float)(ScrollWheelRate * 0.04);
                    }
                }

#endif

                #endregion

                #region Transfrom

                //reset camera angle if needed
                if (cameraYaw > 360)
                    cameraYaw -= 360;
                else if (cameraYaw < 0)
                    cameraYaw += 360;

                //keep camera from rotating a full 90 degrees in either direction
                if (cameraPitch > 89)
                    cameraPitch = 89;
                if (cameraPitch < -89)
                    cameraPitch = -89;

                //update movement (none for this base class)
                movement *= (MoveRate * timeDelta);

                Matrix rotationMatrix;
                Matrix.CreateRotationY(MathHelper.ToRadians(cameraYaw), out rotationMatrix);

                if (movement != Vector3.Zero)
                {
                    Vector3.Transform(ref movement, ref rotationMatrix, out movement);
                    cameraPosition += movement;
                }

                //add in pitch to the rotation
                rotationMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(cameraPitch)) *
                    rotationMatrix;

                //Create a vector pointing the direction the camera is facing.
                Vector3 transformedReference;
                Vector3.Transform(ref cameraReference, ref rotationMatrix,
                    out transformedReference);
                //Calculate the position the camera is looking at.
                Vector3.Add(ref cameraPosition, ref transformedReference, out cameraTarget);

                Matrix.CreateLookAt(ref cameraPosition, ref cameraTarget, ref cameraUpVector,
                    out view);

                #endregion

                #endregion
            }
            else
            {
                #region FPS

                float delta = (float)gameTime.ElapsedGameTime.TotalSeconds;             //for debugging use FPS like camera

                int centerX = Viewport.Width / 2;
                int centerY = Viewport.Height / 2;

                Mouse.SetPosition(centerX, centerY);
                Game.IsMouseVisible = false;

                angle.X += MathHelper.ToRadians((input.MouseState.Y - centerY) * 50 * 0.01f); // pitch
                angle.Y += MathHelper.ToRadians((input.MouseState.X - centerX) * 50 * 0.01f); // yaw

                Vector3 forward = Vector3.Normalize(new Vector3((float)Math.Sin(-angle.Y), (float)Math.Sin(angle.X), (float)Math.Cos(-angle.Y)));
                Vector3 left = Vector3.Normalize(new Vector3((float)Math.Cos(angle.Y), 0f, (float)Math.Sin(angle.Y)));

                if (input.KeyboardState.IsKeyDown(Keys.W))
                    Position -= forward * MoveRate * 10 * delta;

                if (input.KeyboardState.IsKeyDown(Keys.S))
                    Position += forward * MoveRate * 10 * delta;

                if (input.KeyboardState.IsKeyDown(Keys.A))
                    Position -= left * MoveRate * 10 * delta;

                if (input.KeyboardState.IsKeyDown(Keys.D))
                    Position += left * MoveRate * 10 * delta;

                if (input.KeyboardState.IsKeyDown(Keys.PageDown))
                    Position += Vector3.Down * MoveRate * 10 * delta;

                if (input.KeyboardState.IsKeyDown(Keys.PageUp))
                    Position += Vector3.Up * MoveRate * 10 * delta;

                view = Matrix.Identity;
                view *= Matrix.CreateTranslation(-Position);
                view *= Matrix.CreateRotationZ(angle.Z);
                view *= Matrix.CreateRotationY(angle.Y);
                view *= Matrix.CreateRotationX(angle.X);

                #endregion
            }
        }
    }
}
